package com.junxonline.instant.common.util.job;

import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import io.minio.messages.Item;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Minio工具类
 *
 * @author JunX
 * @date 2021-12-10
 */
@Data
@Component
public class MinioUtils {

    /**
     * 服务器地址
     */
    @Value("${minio.endpoint}")
    private String endpoint;

    /**
     * 帐号
     */
    @Value("${minio.accessKey}")
    private String accessKey;

    /**
     * 密码
     */
    @Value("${minio.secretKey}")
    private String secretKey;

    /**
     * 临时上传链接有效期(单位分钟,最小值1,最大值10080)
     */
    @Value("${minio.signedUrlExpire}")
    private Integer signedUrlExpire;

    private MinioClient minioClient = null;

    /**
     * 获取Minio客户端实例
     */
    @PostConstruct
    public void init() {
        if (minioClient == null) {
            minioClient = MinioClient.builder()
                    .endpoint(endpoint)
                    .credentials(accessKey, secretKey)
                    .build();
        }
    }

    /**
     * 查看存储bucket是否存在
     *
     * @param bucketName 存储bucket
     * @return boolean
     */
    public boolean bucketExists(String bucketName) {
        boolean found;
        try {
            found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return found;
    }

    /**
     * 创建存储bucket
     *
     * @param bucketName 存储bucket名称
     * @return boolean
     */
    public boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 获取Object
     *
     * @param bucketName 存储bucket名称
     * @param objectName 对象名称
     * @return String
     */
    public String getObject(String bucketName, String objectName) {
        try {
            GetObjectResponse response = minioClient.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .build());
            return response.object();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 递归获取Objects
     *
     * @param bucketName 存储bucket名称
     * @return Iterable<Result < Item>>
     */
    public Iterable<Result<Item>> recursionGetObjects(String bucketName) {
        try {
            return minioClient.listObjects(ListObjectsArgs.builder()
                    .bucket(bucketName)
                    .recursive(true)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 删除bucket中的所有对象
     *
     * @param bucketName 存储bucket名称
     * @return boolean
     */
    public boolean removeBucketAllObject(String bucketName) {
        try {
            Iterable<Result<Item>> listObjects = this.recursionGetObjects(bucketName);
            for (Result<Item> itemResult : listObjects) {
                this.removeObject(bucketName, itemResult.get().objectName());
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 删除bucket
     *
     * @param bucketName 存储bucket名称
     * @return boolean
     */
    public boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 删除对象
     *
     * @param bucketName 存储bucket名称
     * @param object     对象名称
     * @return boolean
     */
    public boolean removeObject(String bucketName, String object) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(object)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 批量删除对象
     *
     * @param bucketName 存储bucket名称
     * @param objects    对象名称集合
     * @return Iterable<Result < DeleteError>>
     */
    public Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> objects) {
        List<DeleteObject> dos = objects.stream().map(DeleteObject::new).collect(Collectors.toList());
        return minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
    }

    /**
     * 上传对象
     *
     * @param bucketName  存储bucket名称
     * @param objectName  对象名称
     * @param contentType 上传格式
     * @param inputStream 输入流
     * @return boolean
     */
    public boolean putObject(String bucketName, String objectName, String contentType, InputStream inputStream) {
        try {
            minioClient.putObject(PutObjectArgs
                    .builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .contentType(contentType)
                    .stream(inputStream, inputStream.available(), -1)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 生成上传文件临时链接
     *
     * @param bucketName 存储bucket名称
     * @param objectName 对象名称
     * @return String
     */
    public String preSignedPutObject(String bucketName, String objectName) {
        Integer expires = signedUrlExpire;
        if (expires == null) {
            // 设置默认值60分钟
            expires = 60;
        }
        try {
            Map<String, String> reqParams = new HashMap<>();
            reqParams.put("response-content-type", "application/json");
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.PUT)
                    .bucket(bucketName)
                    .object(objectName)
                    .expiry(expires, TimeUnit.MINUTES)
                    .extraQueryParams(reqParams)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
